#ifndef TB_REFLECTION_JSON_INPUT_STREAM_H__
#define TB_REFLECTION_JSON_INPUT_STREAM_H__

#include "../../base/string/utf_string_conversions.hpp"
#include "../../base/assert.hpp"

#include "../buffer_traits.hpp"

TB_NAMESPACE_BEGIN

//refer: http://miloyip.github.io/rapidjson/md_doc_stream.html#CustomStream

template <typename ReadBuffer, typename CharType>
class JsonInputStream {
public:
  BOOST_STATIC_ASSERT(is_read_buffer<ReadBuffer>::value);

  typedef CharType Ch;    //!< Character type of the stream.

  JsonInputStream(ReadBuffer& rb) : rb_(boost::addressof(rb)) {};

  JsonInputStream& operator=(const JsonInputStream& rhs) {
    TB_ASSERT(rb_ != rhs.rb_);
    rb_ = rhs.rb_;
    return *this;
  }

  template <class T> 
  T CharToTChar(const char* c) {
		TB_ASSERT(c);
    return *c;
  }

  template <> 
  char16 CharToTChar<char16>(const char* c) {
    char16 c16 =  UTF8ToUTF16(StringPiece(c, 1)).front();
    return c16;
  }

  //! Read the current character from stream without moving the read cursor.
  Ch Peek() {
    if (rb_->Size() > 0) {
			tuple<const char*, uint32> cc = rb_->PeekBytes(1);
			TB_ASSERT(get<1>(cc) > 0);
      return CharToTChar<Ch>(get<0>(cc));
    }

    return _T('\0');
  }

  //! Read the current character from stream and moving the read cursor to next character.
  Ch Take() {
    if (rb_->Size() > 0) {
      return CharToTChar<Ch>(rb_->ReadValue(1));
    }
    
    return _T('0');
  }

  //! Get the current read cursor.
  //! \return Number of characters read from start.
  size_t Tell() {
    return static_cast<size_t>(rb_->ReadIndex());
  }

  //input stream should not implement write method

  //! Begin writing operation at the current read pointer.
  //! \return The begin writer pointer.
  Ch* PutBegin() { TB_ASSERT(false); return nullptr; }

  //! Write a character.
  void Put(Ch c) { TB_ASSERT(false); return; }

  //! Flush the buffer.
  void Flush() { TB_ASSERT(false); return; }

  //! End the writing operation.
  //! \param begin The begin write pointer returned by PutBegin().
  //! \return Number of characters written.
  size_t PutEnd(Ch* begin) { TB_ASSERT(false); boost::ignore_unused(begin); return 0; }

private:
  ReadBuffer* rb_;
};

TB_NAMESPACE_END

#endif // TB_REFLECTION_JSON_INPUT_STREAM_H__
